using System;
using System.IO;
using System.Diagnostics;

namespace GameFrame
{
    internal static class Log
    {
        private static StreamWriter writer;
        private static object sync;
        private static Action<string> infoCallback;
        private static Action<string> warnCallback;
        private static Action<string> errorCallback;
        private static Action<System.Exception> exnCallback;

        public static void InitForConsole() => Log.Init((Action<string>) (info =>
        {
            Console.ForegroundColor = ConsoleColor.Gray;
            Console.WriteLine(info);
            Console.ForegroundColor = ConsoleColor.Gray;
        }), (Action<string>) (warn =>
        {
            Console.ForegroundColor = ConsoleColor.Yellow;
            Console.WriteLine(warn);
            Console.ForegroundColor = ConsoleColor.Gray;
        }), (Action<string>) (error =>
        {
            Console.ForegroundColor = ConsoleColor.Red;
            Console.WriteLine(error);
            Console.ForegroundColor = ConsoleColor.Gray;
        }), (Action<System.Exception>) (exn =>
        {
            Console.ForegroundColor = ConsoleColor.Red;
            Console.WriteLine(exn.Message);
            Console.WriteLine(exn.StackTrace);
            Console.ForegroundColor = ConsoleColor.Gray;
        }));

        public static void InitFile(string path)
        {
            Log.writer = new StreamWriter((Stream) File.Open(path, FileMode.Create));
            Log.Init(new Action<string>(((TextWriter) Log.writer).WriteLine), new Action<string>(((TextWriter) Log.writer).WriteLine), new Action<string>(((TextWriter) Log.writer).WriteLine), (Action<System.Exception>) (x => Log.writer.WriteLine(x.ToString())));
        }

        public static void Init(
            Action<string> info,
            Action<string> warn,
            Action<string> error,
            Action<System.Exception> exn)
        {
            Log.sync = new object();
            Log.infoCallback = info;
            Log.warnCallback = warn;
            Log.errorCallback = error;
            Log.exnCallback = exn;
        }

        public static void Reset()
        {
            Log.sync = (object) null;
            Log.infoCallback = (Action<string>) null;
            Log.warnCallback = (Action<string>) null;
            Log.errorCallback = (Action<string>) null;
            Log.exnCallback = (Action<System.Exception>) null;
            if (Log.writer == null)
                return;
            try
            {
                Log.writer.Dispose();
            }
            catch
            {
            }
            Log.writer = (StreamWriter) null;
        }

        [Conditional("TRACE")]
        public static void Trace(object value) => Log.Info(value);

        [Conditional("TRACE")]
        public static void Trace(string fmt, params object[] args) => Log.Info(fmt, args);

        public static void Info(object value)
        {
            if (Log.infoCallback == null)
                return;
            lock (Log.sync)
                Log.infoCallback(value == null ? "NULL" : value.ToString());
        }

        public static void Info(string fmt, params object[] args)
        {
            if (Log.infoCallback == null)
                return;
            lock (Log.sync)
                Log.infoCallback(string.Format(fmt, args));
        }

        public static void Info(string fmt, string arg0)
        {
            if (Log.infoCallback == null)
                return;
            lock (Log.sync)
                Log.infoCallback(string.Format(fmt, (object) arg0));
        }

        public static void Info(string fmt, string arg0, string arg1)
        {
            if (Log.infoCallback == null)
                return;
            lock (Log.sync)
                Log.infoCallback(string.Format(fmt, (object) arg0, (object) arg1));
        }

        public static void Info(string fmt, string arg0, string arg1, string arg2)
        {
            if (Log.infoCallback == null)
                return;
            lock (Log.sync)
                Log.infoCallback(string.Format(fmt, (object) arg0, (object) arg1, (object) arg2));
        }

        public static void Warn(string fmt, params object[] args)
        {
            if (Log.warnCallback == null)
                return;
            lock (Log.sync)
                Log.warnCallback(string.Format(fmt, args));
        }

        public static void Warn(string fmt, string arg0)
        {
            if (Log.warnCallback == null)
                return;
            lock (Log.sync)
                Log.warnCallback(string.Format(fmt, (object) arg0));
        }

        public static void Warn(string fmt, string arg0, string arg1)
        {
            if (Log.warnCallback == null)
                return;
            lock (Log.sync)
                Log.warnCallback(string.Format(fmt, (object) arg0, (object) arg1));
        }

        public static void Warn(string fmt, string arg0, string arg1, string arg2)
        {
            if (Log.warnCallback == null)
                return;
            lock (Log.sync)
                Log.warnCallback(string.Format(fmt, (object) arg0, (object) arg1, (object) arg2));
        }

        public static void Warn(object value)
        {
            if (Log.warnCallback == null)
                return;
            lock (Log.sync)
                Log.warnCallback(value == null ? "NULL" : value.ToString());
        }

        public static void Error(string fmt, params object[] args)
        {
            if (Log.errorCallback == null)
                return;
            lock (Log.sync)
                Log.errorCallback(string.Format(fmt, args));
        }

        public static void Error(string fmt, string arg0)
        {
            if (Log.errorCallback == null)
                return;
            lock (Log.sync)
                Log.errorCallback(string.Format(fmt, (object) arg0));
        }

        public static void Error(string fmt, string arg0, string arg1)
        {
            if (Log.errorCallback == null)
                return;
            lock (Log.sync)
                Log.errorCallback(string.Format(fmt, (object) arg0, (object) arg1));
        }

        public static void Error(string fmt, string arg0, string arg1, string arg2)
        {
            if (Log.errorCallback == null)
                return;
            lock (Log.sync)
                Log.errorCallback(string.Format(fmt, (object) arg0, (object) arg1, (object) arg2));
        }

        public static void Error(object value)
        {
            if (Log.errorCallback == null)
                return;
            lock (Log.sync)
                Log.errorCallback(value == null ? "NULL" : value.ToString());
        }

        public static void Exception(System.Exception exn)
        {
            if (Log.exnCallback == null)
                return;
            lock (Log.sync)
                Log.exnCallback(exn);
        }
    }
}